package com.itdfq.shutdown.service;

import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.Connector;

import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Author GocChin
 * @Date 2021/7/23 13:24
 * @Blog: itdfq.com
 * @QQ: 909256107
 * @Description:
 */
@Slf4j
public class CustomShutDown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {

    private static final int TIMEOUT = 10;

    // Connector 属于 Tomcat 抽象组件，功能就是用来接受外部请求，以及内部传递，并返回响应内容
    private volatile Connector connector;

    @Override
    public void customize(Connector connector) {
        this.connector = connector;
    }
    @Override
    public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
        //暂停接受外部请求
        this.connector.pause();
        //获取Connector 对应的线程池
        Executor executor = this.connector.getProtocolHandler().getExecutor();
        if (executor instanceof ThreadPoolExecutor) {
            try {
                log.warn("WEB 准备关闭");
                ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
                //初始化一个关闭任务位于当前待处理完毕的任务之后，并拒绝新的任务提交
                threadPoolExecutor.shutdown();
                if (!threadPoolExecutor.awaitTermination(TIMEOUT, TimeUnit.SECONDS)) {
                    //等待一个已提交的任务执行完成后关闭，并且仅在最大等待时间内进行
                    log.warn("WEB 应用等待关闭超过最大时长" + TIMEOUT + "秒,将强制关闭");
                    threadPoolExecutor.shutdownNow();//强制关闭线程池
                    if (!threadPoolExecutor.awaitTermination(TIMEOUT, TimeUnit.SECONDS)) {
                        log.error("WEB 应用关闭失败！");
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }
    }
}
